#include "Mouse.h"
#include "Logger/Logger.h"
#include "InputDefs.h"

#if defined (_DEBUG)
#include "Memory/MemLeaks.h"
#endif

//-------------------------------------------------
CMouse::CMouse()
	: m_MousePosition(v2iZERO)
	, m_ScreenResolution(v2iZERO)
	, m_Delta(v3iZERO)
	, m_HandleEvent(NULL)
{
	memset(m_bIsDown,	0, sizeof(bool)*3);
	memset(m_bIsUpDown, 0, sizeof(bool)*3);
	memset(m_bIsDownUp, 0, sizeof(bool)*3);
}

//-------------------------------------------------
CMouse::~CMouse()
{

}

//-------------------------------------------------
bool CMouse::Initialize(LPDIRECTINPUT8 _directInput, HWND _hWnd, const Vect2u& _screenRes, bool _bExclusiveMode)
{
	bool l_bIsOk;

	l_bIsOk = CInputDevice::Initialize(_directInput, _hWnd, GUID_SysMouse, &c_dfDIMouse, _bExclusiveMode);
	
	if(l_bIsOk)
	{
		memset(m_bIsDown,	0, sizeof(bool)*3);
		memset(m_bIsUpDown, 0, sizeof(bool)*3);
		memset(m_bIsDownUp, 0, sizeof(bool)*3);
		m_MousePosition		= v2iZERO;
		m_ScreenResolution	= Vect2i(_screenRes.x, _screenRes.y);

		// activate event notification for the mouse
		m_HandleEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
		l_bIsOk = (m_HandleEvent != NULL);

		if(l_bIsOk)
		{
			l_bIsOk = SUCCEEDED(m_DIDevice->SetEventNotification(m_HandleEvent));
			if(l_bIsOk)
			{
				// create buffered input for the mouse
				DIPROPDWORD dipdw;
				dipdw.diph.dwSize       = sizeof(DIPROPDWORD);
				dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
				dipdw.diph.dwObj        = 0;
				dipdw.diph.dwHow        = DIPH_DEVICE;
				dipdw.dwData            = BUFFER_SIZE;

				l_bIsOk = SUCCEEDED( m_DIDevice->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph));

				if (l_bIsOk)
				{
					// acquire the device to make it work
					m_DIDevice->Acquire();
					LOGGER->AddNewLog(ELL_INFORMATION, "Mouse:: mouse online");
				}
			}
		}
	}

	if(!l_bIsOk)
	{
		CInputDevice::Uninitialize();
	}

	return l_bIsOk;
}

//-------------------------------------------------
bool CMouse::Update()
{
	DIDEVICEOBJECTDATA od[BUFFER_SIZE];
	DWORD dwNumElem = BUFFER_SIZE;

	m_Delta = v3iZERO;

	ZeroMemory(&od[0], sizeof(DIDEVICEOBJECTDATA)*BUFFER_SIZE);

	// try to get the data from the mouse
	if (FAILED(GetData(Input::IDV_MOUSE, &od[0], &dwNumElem))) 
	{
		return false;
	}

	// clear those
	m_bIsDownUp[0] = m_bIsDownUp[1] = m_bIsDownUp[2] = false;
	m_bIsUpDown[0] = m_bIsUpDown[1] = m_bIsUpDown[2] = false;


	// now we have 'dwNumElem' of mouse events
	for (DWORD i=0; i<dwNumElem; ++i)
	{
		switch (od[i].dwOfs)
		{
			// MOVEMENT
		case DIMOFS_X: 
			{
				m_MousePosition.x += od[i].dwData;
				m_Delta.x = od[i].dwData;

				if (m_MousePosition.x < 0)
					m_MousePosition.x = 0;
				else if (m_MousePosition.x > m_ScreenResolution.x)
					m_MousePosition.x = m_ScreenResolution.x;
			} 
			break;

		case DIMOFS_Y: 
			{
				m_MousePosition.y += od[i].dwData;
				m_Delta.y = od[i].dwData;

				if (m_MousePosition.y < 0)
					m_MousePosition.y = 0;
				else if (m_MousePosition.y > m_ScreenResolution.y)
					m_MousePosition.y = m_ScreenResolution.y;
			} 
			break;

		case DIMOFS_Z: 
			{
				m_Delta.z = od[i].dwData;
			} 
			break;

			// BUTTON STATES
		case DIMOFS_BUTTON0:
			{
				if (od[i].dwData & 0x80) {
					if (!m_bIsDown[0])
						m_bIsUpDown[0] = true;
					m_bIsDown[0] = true;
				}
				else {
					if (m_bIsDown[0])
						m_bIsDownUp[0] = true;

					m_bIsDown[0] = false;
				}
			}
			break;

		case DIMOFS_BUTTON1:
			{
				if (od[i].dwData & 0x80){
					if (!m_bIsDown[1])
						m_bIsUpDown[1] = true;
					m_bIsDown[1] = true;
				}
				else {
					if (m_bIsDown[1])
						m_bIsDownUp[1] = true;

					m_bIsDown[1] = false;
				}
			}
			break;

		case DIMOFS_BUTTON2:
			{
				if (od[i].dwData & 0x80){
					if (!m_bIsDown[2])
						m_bIsUpDown[2] = true;
					m_bIsDown[2] = true;
				}
				else {
					if (m_bIsDown[2])
						m_bIsDownUp[2] = true;

					m_bIsDown[2] = false;
				}
			}
			break;
		}; // END switch (od[i].dwOfs)
	} // END for (DWORD i=0; i<dwNumElem; i++)

	return true;
}

//-------------------------------------------------
bool CMouse::IsDown(uint32 nBtn) const
{
	if (nBtn<3) 
		return m_bIsDown[nBtn]; 
	
	return false;
}

//-------------------------------------------------
bool CMouse::IsDownUp(uint32 nBtn) const
{
	if (nBtn<3) 
		return m_bIsDownUp[nBtn]; 
	
	return false;
}

//-------------------------------------------------
bool CMouse::IsUpDown(uint32 nBtn) const
{
	if (nBtn<3) 
		return m_bIsUpDown[nBtn]; 
	
	return false;
}

//-------------------------------------------------
const Vect3i& CMouse::GetMouseDelta() const
{
	return m_Delta;
}